package com.feng.common.db.querydsl;

import com.feng.common.web.Range;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.querydsl.core.QueryResults;
import com.querydsl.core.Tuple;
import com.querydsl.core.types.Expression;
import com.querydsl.core.types.Path;
import com.querydsl.jpa.impl.JPAQuery;

import java.util.*;

/**
 * FetchResponse Builder
 * @author Lee
 * @param <T>
 */
public class FetchResponseBuilder<T> {

    private Range range;

    public FetchResponseBuilder(){}

    /**
     * 分页
     * @param range
     * @return FetchResponseBuilder
     */
    public FetchResponseBuilder<T> range(Range range) {
        this.range = range;
        return this;
    }

    public FetchResponse<T> build(JPAQuery<T> jpaQuery) {
        FetchResponse<T> fetchResponse = new FetchResponse<>();
        QueryResults<T> queryResults = buildRange(jpaQuery, fetchResponse);
        fetchResponse.setData(queryResults.getResults());
        return fetchResponse;
    }

    @SuppressWarnings("unchecked")
    public FetchResponse<Map<String,Object>> buildAsMap(JPAQuery<Tuple> jpaQuery, Expression<?>... exprs) {
        FetchResponse<Map<String,Object>> fetchResponse = new FetchResponse<>();
        QueryResults<Tuple> queryResults = null;
        queryResults = buildRange(jpaQuery, (FetchResponse<T>) fetchResponse);

        ArrayList<Map<String,Object>> resultData = Lists.newArrayList();
        queryResults.getResults().forEach(tuple -> {
            HashMap<String, Object> map = Maps.newHashMap();
            Arrays.asList(exprs).forEach(expression -> {
                map.put(((Path<?>) expression).getMetadata().getName(),tuple.get(expression));
            });
            resultData.add(map);
        });

        fetchResponse.setData(resultData);
        return (FetchResponse<Map<String, Object>>) fetchResponse;
    }

    private <E> QueryResults<E> buildRange(JPAQuery<E> jpaQuery, FetchResponse<T> fetchResponse) {
        QueryResults<E> queryResults;
        if (!Objects.isNull(range)) {
            queryResults = jpaQuery.limit(range.getLength()).offset(range.getStart()).fetchResults();
            fetchResponse.setStart(range.getStart());
        }else {
            queryResults = jpaQuery.fetchResults();
        }
        fetchResponse.setRows(queryResults.getTotal());
        return queryResults;
    }


}
